<?php
declare(strict_types=1);

namespace Reven\HyperfRedisBasics;



use Reven\HyperfRedisBasics\occ\Version;
use Reven\HyperfRedisBasics\lock\Lock;

class Entrance
{
    protected array $params;

    protected string $prefix;

    protected string $redisKey;

    /**
     * Entrance constructor.
     * @param array $keyParams 根据arr生成redis key
     * @param string $keyPrefix redis key前缀
     */
    public function __construct(array $keyParams,string $keyPrefix)
    {
        $this->params=$keyParams;
        $this->prefix=$keyPrefix;
        $this->redisKey=$this->key();
    }

    /**
     * @return string
     */
    public function getRedisKey(): string
    {
        return $this->redisKey;
    }

    private function key():string {
        $sortStr=self::sortGenKey($this->params);
        return $this->prefix.$sortStr;
    }

    /**
     * redis 锁
     * @param int $ttl 有效期单位毫秒
     * @param bool $lock 是否为锁 如果不是 仅判断有效时间内key是否存在
     * @return Lock
     */
    public function lockInstance(int $ttl,bool $lock=false):Lock{
        return new Lock($this->redisKey,$ttl,$lock);
    }

    /**
     * redis occ 版本号实现
     * redis 版本号预防并发在事物中调用 提交调用commit
     * @param int $ttl
     * @return Version
     * @throws exception\ConcurrencyException 并发异常
     */
    public function occVersionInstance(int $ttl=8640000){
        return new Version($this->redisKey,$ttl);
    }

    public static function sortGenKey($arr):string {
        $output=[];
        self::sortArrItem($arr,$output);
        return implode('&',$output);
    }

    /**
     * 数据按key升序排序key,value拼接
     * @param $arr
     * @param $output
     * @param string $level
     */
    public static function sortArrItem($arr,&$output,$level=''){
        ksort($arr);
        foreach ($arr as $key=>$v){
            if (is_object($v)){
                $v=(array)$v;
            }
            if (is_array($v)){
                self::sortArrItem($v,$output,$level.$key);
            }else{
                if (is_string($v)){
                    $v=trim($v);
                }
                $output[]=$level==''?"{$key}_{$v}":"{$level}_{$key}={$v}";
            }
        }
    }
}